package com.github.hgkmail.hello.web;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.github.hgkmail.hello.annotation.PrintMethod;
import com.github.hgkmail.hello.annotation.Walk;
import com.github.hgkmail.hello.entity.ry.SysMenu;
import com.github.hgkmail.hello.dao.ry.SysMenuDao;
import com.github.hgkmail.hello.exception.CommonException;
import com.github.hgkmail.hello.property.MyConfig;
import com.github.hgkmail.hello.sentinel.CustomerBlockHandler;
import com.github.hgkmail.hello.util.VelocityUtil;
import com.github.hgkmail.hello.vo.BaseVo;
import com.github.hgkmail.hello.vo.LayuiTableVo;
import com.github.hgkmail.hi.starter.HiService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.page.PageMethod;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.subject.Subject;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.MessageSource;
import org.springframework.context.event.*;
import org.springframework.context.event.EventListener;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.support.RequestHandledEvent;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import javax.validation.constraints.Min;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.util.*;

import static com.github.hgkmail.hello.constant.CommonResponse.*;

@RestController
@RequestMapping(value = "/test")
@Validated
public class TestController {

    private static final Logger logger = LoggerFactory.getLogger(TestController.class);

    @Autowired
    ApplicationContext applicationContext;

    @Autowired
    HiService hiService;

    @Autowired
    SysMenuDao sysMenuDao;

    @Autowired
    MessageSource messageSource;

    @Autowired
    Validator validator;

    @Value("${hgk.hi.greet}")
    String configGreet;

    @Autowired
    MyConfig myConfig;

    @Autowired
    JdbcTemplate jdbcTemplate;

    @Autowired
    VelocityEngine velocityEngine;

    @Autowired
    VelocityUtil velocityUtil;

    @GetMapping("/add")
    @SentinelResource(value="add"
            ,blockHandlerClass= CustomerBlockHandler.class
            ,blockHandler="handlerException")
    public String testA(HttpServletRequest request) {
        try {
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "add";
    }

    @GetMapping("/sysMenu/getById")
    public BaseVo getSysMenuById(@RequestParam("id")Integer id) {
        SysMenu sysMenu = sysMenuDao.getById(id);
        return new BaseVo(CODE_SUCCESS, MSG_SUCCESS, sysMenu);
    }

    //@RequestBody要求客户端：1.请求头application/json  2.请求体json字符串
    @PostMapping("/sysMenu/updateById")
    public BaseVo getSysMenuById(@RequestBody SysMenu sysMenu) {
        sysMenuDao.updateById(sysMenu);
        return new BaseVo(CODE_SUCCESS, MSG_SUCCESS, sysMenu);
    }

    @GetMapping("/layui/table")
    public LayuiTableVo layuiTable(@RequestParam(value = "page", defaultValue = "1") Integer page,
                                   @RequestParam(value = "limit", defaultValue = "10") Integer limit) {
        PageHelper.startPage(page, limit);
        List<SysMenu> list = sysMenuDao.findAll();
        PageInfo<SysMenu> pageInfo = new PageInfo<>(list);

        return new LayuiTableVo(CODE_SUCCESS, MSG_SUCCESS, list, pageInfo.getTotal());
    }

    @GetMapping("/entity")
    public BaseVo entity() {
        List<Map<String, Object>> res = jdbcTemplate.queryForList(velocityUtil.getTableSchema("ry", "sys_menu"));

        // 载入（获取）模板对象
        Template t = velocityEngine.getTemplate("code-maker/Entity.vm");
        VelocityContext ctx = new VelocityContext();
        // 域对象加入参数值
        ctx.put("pkgName", "com.github.hgkmail.hello.entity");
        ctx.put("clsName", "SysMenu");
        ctx.put("clsFields", res);
        ctx.put("util", velocityUtil);
        StringWriter sw = new StringWriter();
        t.merge(ctx, sw);
        System.out.println(sw.toString());

        return new BaseVo(CODE_SUCCESS, MSG_SUCCESS, res);
    }

    @GetMapping("/error")
    public BaseVo error() {
        return new BaseVo(CODE_FAIL, MSG_FAIL, "没有访问权限");
    }

    @GetMapping("/index")
    public BaseVo index() {
        return new BaseVo(CODE_SUCCESS, MSG_SUCCESS, "首页");
    }

    @GetMapping("/logout")
    public BaseVo logout() {
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        return new BaseVo(CODE_SUCCESS, MSG_SUCCESS, "已登出");
    }

    @GetMapping("/login")
    public BaseVo login(@RequestParam(value = "ok", defaultValue = "0") int ok) {
        if (ok==1) {
            Subject subject = SecurityUtils.getSubject();
            UsernamePasswordToken token = new UsernamePasswordToken("test", "test123");
            subject.login(token);
            return new BaseVo(CODE_SUCCESS, MSG_SUCCESS, "登录成功");
        } else {
            return new BaseVo(CODE_SUCCESS, MSG_SUCCESS, "请登录");
        }
    }

    @EventListener(ContextRefreshedEvent.class)
    public void appCtxRefreshEvent(ContextRefreshedEvent event) {
        logger.info("ApplicationContext容器初始化完成。。。");
    }

    //Started这个事件看不到日志
    @EventListener(ContextStartedEvent.class)
    public void appCtxStartedEvent(ContextStartedEvent event) {
        logger.info("ApplicationContext容器启动。。。");
    }

    //Stopped这个事件看不到日志
    @EventListener(ContextStoppedEvent.class)
    public void appCtxStopEvent(ContextStoppedEvent event) {
        logger.info("ApplicationContext容器停止。。。");
    }

    @EventListener(ContextClosedEvent.class)
    public void appCtxClosedEvent(ContextClosedEvent event) {
        logger.info("ApplicationContext容器关闭。。。");
    }

    @EventListener(RequestHandledEvent.class)
    public void appCtxRequestEvent(RequestHandledEvent event) {
        logger.info("ApplicationContext容器收到request。。。{}", event.getDescription());
    }

    @GetMapping("appCtx")
    public BaseVo appCtx() {
        Map<String, Object> map = new HashMap<>();
        map.put("appName", applicationContext.getApplicationName());
        map.put("displayName", applicationContext.getDisplayName());
        map.put("MyConfigBean", applicationContext.getBeansOfType(MyConfig.class));
        map.put("RestController", applicationContext.getBeansWithAnnotation(RestController.class).keySet());
        return new BaseVo(CODE_SUCCESS, MSG_SUCCESS, map);
    }

    @RequiresRoles("SuperAdmin")
    @PrintMethod()
    @GetMapping("/prop")
    public BaseVo prop() {
        Map<String, Object> map = new HashMap<>();
        map.put("configGreet", configGreet);
        map.put("myConfig", myConfig);
        return new BaseVo(CODE_SUCCESS, MSG_SUCCESS, map);
    }

    @PrintMethod(showArgs = true)
    @Walk(word = "see greet")
    @GetMapping(value = "/hello")
    public BaseVo hello(@RequestParam("time")@Min(value = 10, message = "time不能小于10") Integer time)  {
        String helloTom = messageSource.getMessage("hello.tom", null, LocaleContextHolder.getLocale());
        BaseVo vo = new BaseVo();
        vo.setCode(CODE_SUCCESS);
        vo.setMsg(MSG_SUCCESS+time+helloTom);
        vo.setData(hiService.getGreeting());
        return vo;
    }

    @PostMapping(value = "/formUpload")
    public BaseVo formUpload(@RequestParam("file")MultipartFile multipartFile) throws CommonException {
        if (Objects.isNull(multipartFile) || multipartFile.isEmpty()) {
            throw new CommonException("上传文件异常");
        }
        String dir = makeUploadDir();
        if (dir.isEmpty()) {
            throw new CommonException("上传目录异常");
        }
        String originFileName = multipartFile.getOriginalFilename();
        File target = new File(dir, originFileName);
        if (target.exists()) {
            throw new CommonException("存在同名文件");
        }
        try {
            multipartFile.transferTo(target);
        } catch (IOException e) {
            throw new CommonException(e.getMessage());
        }
        return new BaseVo(CODE_SUCCESS, MSG_SUCCESS, target.getAbsoluteFile());
    }

    @Walk(word = "see menu")
    @GetMapping("/getSysMenu")
    public BaseVo getSysMenu(
            @RequestParam(name = "pageNum", defaultValue = "1") Integer pageNum,
            @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) {

        PageMethod.startPage(pageNum, pageSize);
        List<SysMenu> sysMenuList = sysMenuDao.findAll();
        for (SysMenu menu:sysMenuList) {
            Set<ConstraintViolation<SysMenu>> cvSet = validator.validate(menu);
            for (ConstraintViolation<SysMenu> cv:cvSet) {
                logger.warn("ConstraintViolation {} {}",cv.getRootBean(), cv.getMessage());
            }
        }
        PageInfo<SysMenu> pageInfo = new PageInfo<>(sysMenuList);
        return new BaseVo(CODE_SUCCESS, MSG_SUCCESS, pageInfo);
    }

    private String makeUploadDir() {
        //在当前项目根目录下新建文件夹
        String path = "uploadFiles/";
        File dir = new File(path);
        if (!dir.exists()) {
            boolean res = dir.mkdirs();
            if (!res) {
                return "";
            }
        }
        return dir.getAbsolutePath();
    }
}
